﻿<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue.js用户添加权限管理模块功能 - 站长素材</title>

<script src="./js/vue.min.js"></script>
<link rel="stylesheet" href="./css/main.css">

<!-- 饿了么 图标库 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 饿了么 引入组件库 -->
<script src="js/index.js"></script>

<style>
.pageTitle {
  text-align: center;
  font-size: 18px;
  background: #91ccb1;
  height: 40px;
  line-height: 40px;
  padding: 0 10px;
}
</style>
</head>

<body>

<div id="app">
    <p class="pageTitle" style="margin-bottom: 10px">权限管理模块</p>
    
    <p class="textL" style="margin-bottom: 10px;padding: 0 20px;">
      角色列表：<el-button @click="addRole" size="mini" type="primary"
        >增加角色</el-button
      >
    </p>

    <!-- 参考链接1：https://blog.csdn.net/Lchannel/article/details/77317751 -->

    <div style="margin:20px;">
      <el-table :data="allRole" border size="mini">
        <el-table-column type="index" label="序号" width="60"></el-table-column>
        <el-table-column prop="name" label="角色名" width="200"></el-table-column>
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-button type="primary" size="mini" @click="editRow(scope.row)">编辑</el-button>
            <el-button type="danger" size="mini" @click="delRow(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>

    <!-- 弹框部分 -->
    <el-dialog :title="isAdd ? '新增角色' : '修改角色'" class="myDialog blueHead textL" :visible.sync="showRight"
      :close-on-click-modal="false" width="1200px">
      <div style="padding: 0 15px;">
        <p v-if="isAdd" style="background-color: #eee; padding: 5px">
          角色名称：
          <el-input style="width: 250px" size="mini" @blur="blurFun(currentRole.name)" v-model="currentRole.name">
          </el-input>
        </p>
        <p v-else>当前角色：{{ currentRole.name }}</p>
        <div style="max-height: 560px; overflow: auto;">

          <todo-box class="sonMenu textL mg-t20" style="border: 1px solid #eee;"
            v-for="(item,index) in currentRole.allRight" 
            v-bind:item="item" 
            v-bind:key="item.name+index"
            @topClicka="topClickF" 
            @titleClickson="titleClickFa">
          </todo-box>

          <!--
            现在我们为每个 todo-item 提供待办项对象
            待办项对象是变量，即其内容可以是动态的。
            我们也需要为每个组件提供一个“key”，晚些时候我们会做个解释。
          -->
          <!-- <div id="app-7">
            <ol>
              <todo-item
                v-for="item in groceryList"
                v-bind:todo="item"
                v-bind:key="item.id">
              </todo-item>
            </ol>
          </div> -->

          <!-- 
            <anchored-heading :level="1">
            asdfasdf
          </anchored-heading>
          <button-counter></button-counter> -->
        </div>
        <p style="text-align: right; margin-bottom: 15px; margin-top: 10px">
          <el-button @click="showRight = false" size="mini">取 消</el-button>
          <el-button v-if="isAdd" size="mini" type="primary" @click="saveRole(currentRole)">确 定</el-button>
          <el-button v-else size="mini" type="primary" @click="updateRole(currentRole)">修 改</el-button>
        </p>
      </div>
    </el-dialog>
  </div>


  <script>

    // 1.至于过程和实现，有不懂的，都可以问喔！我的微信号 yizheng369
    // 2.github源码地址https://github.com/banana618859/workArrange.git


    Vue.component('todo-item', {
      props: ['todo'],
      template: '<li>{{ todo.text }}</li>'
    })

    // 参考链接2：https://blog.csdn.net/Lchannel/article/details/77317751

    // render Vue.component注册的组件，必须要在vue实例创建之前（即在 new Vue()之前），否则不生效
    Vue.component('anchored-heading22', {
      render: function (createElement) {
        console.warn('render：', this);
        return createElement(
          'h' + this.level,   // 标签名称
          this.$slots.default // 子节点数组
        )
      },
      props: {
        level: {
          type: Number,
          required: true
        }
      }
    })

    Vue.component('content-box', {
      template: `
              <div style="border:1px solid #eee;" class="pd-t10-b20 pd-lr10">
                <span v-for="(item,index) in data" :key="faName+'_'+item.name+index" style="margin-right:10px;">
                  <el-checkbox v-model="item.check" @change="changeFun(faName+'_'+item.name, item.check)">{{item.name}}</el-checkbox>
                </span>
              </div>`,
      props: {
        data: {
          type: Array,
          default: () => []
        },
        faName: {
          type: String,
          default: ''
        }
      },
      methods: {
        changeFun() {
          console.error('content-box-changeFun:');
          this.$emit('clickOne', ...arguments)
        }
      },
      data() {
        return {}
      }
    })


    Vue.component('list-box', {
      template: `
              <div>
                <div v-for="(item,index) in data" :key="item.name+index" class="sonMenu" style="padding:5px; margin-top:10px; margin-bottom:10px;" >
                  <p style="background-color: #d5dfdc;" class="pd-t2-l10">
                    <el-checkbox v-model="item.check" @change="titleClick(faName+'_'+item.name,item.check)">{{item.name}}</el-checkbox>
                  </p>
                  <list-box v-if="item.children && item.children[0].children" :data="item.children" :faName="faName+'_'+item.name"></list-box>
                  <content-box v-else :data="item.children" :faName="faName+'_'+item.name" @clickOne="clickOne"></content-box>
                  
                </div>
              </div>`,
      props: {
        data: {
          type: Array,
          default: () => []
        },
        faName: {
          type: String,
          default: ''
        }
      },
      methods: {
        titleClick() {
          console.error('l-b-titleClick:', arguments);
          this.$emit('titleClick', ...arguments)
        },
        clickOne(a) {
          console.error('l-b-clickOne:', arguments);
          this.$emit('clickOne', ...arguments)
        }
      },
      data() {
        return {

        }
      }
    })

    Vue.component('button-counter', {
      data: function () {
        return {
          count: 0
        }
      },
      template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
    })

    // 创建组件
    var login = {
      template: "<h1>登录组件</h1>"
    }

    var vm = new Vue({
      el: '#app',
      data() {
        return {
          bllRight: [],
          groceryList: [],
          isAdd: true,
          showRight: false,
          baseRole: {
            name: "",
            allRight: [
              {
                name: "用户权限管理",
                check: true,
                children: [
                  {
                    name: "用户管理",
                    check: true,
                    children: [
                      {
                        name: "增",
                        action: "add",
                        check: true
                      },
                      {
                        name: "删",
                        action: "delete",
                        check: true
                      },
                      {
                        name: "查",
                        action: "read",
                        check: true
                      },
                      {
                        name: "改",
                        action: "update",
                        check: true
                      },
                    ],
                  },
                  {
                    name: "角色管理",
                    check: true,
                    children: [
                      {
                        name: "增",
                        action: "add",
                        check: true
                      },
                      {
                        name: "删",
                        action: "delete",
                        check: true
                      },
                    ],
                  },
                ],
              },
              {
                name: "库存管理",
                check: true,
                children: [
                  {
                    name: "入库管理",
                    check: true,
                    children: [
                      {
                        name: "增",
                        action: "add",
                        check: true
                      },
                      {
                        name: "删",
                        action: "delete",
                        check: true
                      },
                    ],
                  },
                  {
                    name: "出库管理",
                    check: true,
                    children: [
                      {
                        name: "增",
                        action: "add",
                        check: true
                      },
                      {
                        name: "删",
                        action: "delete",
                        check: true
                      },
                    ],
                  },
                  {
                    name: "盘点管理",
                    check: true,
                    children: [
                      {
                        name: "增",
                        action: "add",
                        check: true
                      },
                      {
                        name: "删",
                        action: "delete",
                        check: true
                      },
                    ],
                  },
                ],
              },
              {
                name: "分类管理",
                check: true,
                children: [
                  {
                    name: "物料管理",
                    check: true,
                    children: [
                      {
                        name: "增",
                        action: "add",
                        check: true
                      },
                      {
                        name: "删",
                        action: "delete",
                        check: true
                      },
                    ],
                  },
                  {
                    name: "分类管理",
                    check: true,
                    children: [
                      {
                        name: "增",
                        action: "add",
                        check: true
                      },
                      {
                        name: "删",
                        action: "delete",
                        check: true
                      },
                    ],
                  },
                ],
              },
              {
                name: "其他管理",
                check: true,
                children: [
                  {
                    name: "其他管理1",
                    check: true,
                    children: [
                      {
                        name: "增",
                        action: "add",
                        check: true
                      },
                      {
                        name: "删",
                        action: "delete",
                        check: true
                      },
                    ],
                  },
                  {
                    name: "其他管理2",
                    check: true,
                    children: [
                      {
                        name: "增",
                        action: "add",
                        check: true
                      },
                      {
                        name: "删",
                        action: "delete",
                        check: true
                      },
                    ],
                  },
                ],
              },
            ],
          },
          currentRole: {
            name: "",
            allRight: [],
          },
          allRole: [],
        };
      },
      created() { },
      components: {
        'todo-box': {
          props: ['item'],
          template: `<div>
            <p class="title pd-t2-l10">
              <el-checkbox
                v-model="item.check"
                @change="topClick(item.name, item.check)"
                >{{ item.name }}</el-checkbox>
            </p>
            <div style="border: 1px solid #ccc; overflow: auto; height: 210px">
              <list-box 
                v-if="item.children && item.children[0].children" 
                :data="item.children" 
                :faName="item.name" 
                @clickOne="sonTitleClick" 
                @titleClick="sonTitleClick">
              </list-box>
              <content-box v-else :data="item.children" :faName="item.name" ></content-box>
            </div>
          </div>`,
          methods: {
            // 情况1：操作最顶级时，以下所有级都受影响（父亲选中，儿子都选中）
            topClick() {
              console.error('todo-b-topClick:', ...arguments, this, vm, this === vm);

              // this.$emit('topClicka', ...arguments)
              // 此处只能用全局对象vm直接调用了
              vm.topClickF(...arguments)
            },
            sonTitleClick() {
              console.error('todo-b-sonTitleClick:', arguments);
              // this.$emit('titleClickson', ...arguments)
              // 此处只能用全局对象vm直接调用了
              vm.titleClickFa(...arguments)
            }
          },
        }
      },
      methods: {
        // 情况1：操作最顶级时，以下所有级都受影响（父亲选中，儿子都选中）
        topClickF(name, status) {
          console.log('最顶层--topClickF');
          let theRight = this.currentRole.allRight
          console.error("rb-title:", name, status, theRight);
          for (let i = 0; i < theRight.length; i++) {
            if (theRight[i].name == name) {
              if (!theRight[i].hasOwnProperty("check")) {
                this.$set(theRight[i], "check", status);
              } else {
                theRight[i].check = status;
              }
              if (theRight[i].children) {
                this.loopCheck(theRight[i].children, status);
              } else if (theRight[i].data) {
                this.loopCheck(theRight[i].data, status);
              }
            }
          }
          // console.error('最后结果：',theRight);
        },
        loopCheck(arr, status) {
          for (let i = 0; i < arr.length; i++) {
            if (!arr[i].hasOwnProperty("check")) {
              this.$set(arr[i], "check", status);
            } else {
              arr[i].check = status;
            }

            if (arr[i].children) {
              this.loopCheck(arr[i].children, status);
            } else if (arr[i].data) {
              this.loopCheck(arr[i].data, status);
            }
          }
        },
        // 情况2：不是操作最顶级时，区别对待（规则：有一个儿子选中，父亲就选中；所有儿子都不选中，父亲才不选中）
        titleClickFa() {
          console.log('最顶层--titleClickFa', arguments);
          if (!arguments[0]) {
            return
          }
          let rootArr = arguments[0].split("_");
          let status = arguments[1];
          console.error("rb-titleClickFa:", rootArr, status);
          let allFa = [];
          let arr = this.currentRole.allRight;
          let one = rootArr.shift();
          for (let i = 0; i < arr.length; i++) {
            if (arr[i].name == one) {
              if (!status) {
                // 情况2-1：取消时 false
                if (rootArr.length) {
                  // 取消勾选--收集父级（因为考虑到可能父级会受到其他子类影响，因此先将父级收集起来）
                  allFa.push(arr[i]);
                  this.loopFindSon(arr[i].children, rootArr, status, allFa);
                }
              } else {
                // 情况2-2：选中时 true（因为如果有一个儿子选中，父亲就选中，那么可以直接勾选父亲了。）
                if (!arr[i].hasOwnProperty("check")) {
                  this.$set(arr[i], "check", status);
                } else {
                  arr[i].check = status;
                }
                // console.error('arr[i].check:',arr[i].name, status);
                if (rootArr.length) {
                  // 如果还没找到最底层，继续循环找下去
                  this.loopFindSon(arr[i].children, rootArr, status);
                } else {
                  if (!arr[i].children) {
                    return
                  }
                  // 如果找到了操作的那一层，如果该层下面还有儿子，就将儿子都选中
                  for (let j = 0; j < arr[i].children.length; j++) {
                    let sonOne = arr[i].children[j];
                    if (!sonOne.hasOwnProperty("check")) {
                      this.$set(sonOne, "check", status);
                    } else {
                      sonOne.check = status;
                    }
                  }
                }
              }
            }
          }
          let realFa = JSON.parse(JSON.stringify(allFa))
          // console.error('realFa',realFa);
          if (!status && allFa.length) {
            let needFa = allFa.pop();

            let hasTrue = false;
            for (let i = 0; i < needFa.children.length; i++) {
              if (needFa.children[i].check) {
                hasTrue = true;
                break;
              }
            }
            if (!needFa.hasOwnProperty("check")) {
              this.$set(needFa, "check", hasTrue);
            } else {
              needFa.check = hasTrue;
            }
            if (allFa.length) {
              this.loopCheckFa(allFa);
            }
          }

          // console.error('最后结果：',theRight);
        },
        loopCheckFa(allFa) {
          let needFa = allFa.pop();
          let hasTrue = false;
          for (let i = 0; i < needFa.children.length; i++) {
            if (needFa.children[i].check) {
              hasTrue = true;
              break;
            }
          }
          if (!needFa.hasOwnProperty("check")) {
            this.$set(needFa, "check", hasTrue);
          } else {
            needFa.check = hasTrue;
          }
          if (allFa.length) {
            this.loopCheckFa(allFa);
          }
        },
        loopFindSon(arr, rootArr, status, allFa) {
          let one = rootArr.shift();
          for (let i = 0; i < arr.length; i++) {
            if (arr[i].name == one) {
              if (!status) {

                if (rootArr.length) {
                  // 收集父级
                  allFa.push(arr[i]);
                  this.loopFindSon(arr[i].children, rootArr, status, allFa);
                } else {
                  // 如果已经找到操作的那一层了。因为父亲不选中，就把该层下面的儿子都不选中
                  if (arr[i].children) {
                    for (let j = 0; j < arr[i].children.length; j++) {
                      let ason = arr[i].children[j]
                      if (!ason.hasOwnProperty("check")) {
                        this.$set(ason, "check", status);
                      } else {
                        ason.check = status;
                      }
                    }
                  }

                }
              } else {
                if (!arr[i].hasOwnProperty("check")) {
                  this.$set(arr[i], "check", status);
                } else {
                  arr[i].check = status;
                }
                // console.error('arr[i].check:',arr[i].name, status);
                if (rootArr.length) {
                  this.loopFindSon(arr[i].children, rootArr, status);
                } else {
                  if (!arr[i].children) {
                    return
                  }
                  // 如果已经找到操作的那一层了。因为父亲选中，就把该层下面的儿子都选中
                  for (let j = 0; j < arr[i].children.length; j++) {
                    let sonOne = arr[i].children[j];
                    if (!sonOne.hasOwnProperty("check")) {
                      this.$set(sonOne, "check", status);
                    } else {
                      sonOne.check = status;
                    }
                  }
                }
              }
            }
          }
        },
        editRow(row) {
          this.currentRole = JSON.parse(JSON.stringify(row));
          this.showRight = true;
          this.isAdd = false;
        },
        pageSelectFun(a, b) {
          console.log("pageSelectFun", a, b);
        },
        checkSameName(name) {
          let hasOne = false;
          for (let i = 0; i < this.allRole.length; i++) {
            if (this.allRole[i].name == name) {
              hasOne = true;
              break;
            }
          }
          return hasOne;
        },
        blurFun(name) {
          console.log("blurFun，这里可以检查是否有重复命名");
          let hasOne = this.checkSameName(name)
          if (hasOne) {
            this.$message({
              message: '该角色名已被占用！',
              type: 'warning'
            })
          }
        },
        saveRole(row) {
          if (!row.name) {
            this.$message({
              message: "请填写角色名！",
              type: "warning",
            });
            return;
          }
          let hasOne = this.checkSameName(row.name)
          if (hasOne) {
            this.$message({
              message: '该角色名已被占用！',
              type: 'warning'
            })
            return;
          }
          this.allRole.push(JSON.parse(JSON.stringify(row)));
          this.showRight = false;
        },
        updateRole(row) {
          console.log("updateRole");
          for (let i = 0; i < this.allRole.length; i++) {
            if (this.allRole[i].name == row.name) {
              // 此处要深拷贝一下，否则会污染
              this.allRole[i].allRight = JSON.parse(JSON.stringify(this.currentRole.allRight));
              break;
            }
          }
          this.showRight = false;
        },
        addRole() {
          console.error('addRole:', this.baseRole);
          this.currentRole = JSON.parse(JSON.stringify(this.baseRole));
          // this.bllRight = JSON.parse(JSON.stringify(this.baseRole.allRight));
          this.showRight = true;
          this.isAdd = true;

          setTimeout(() => {
            this.groceryList = [
              { id: 0, text: '蔬菜' },
              { id: 1, text: '奶酪' },
              { id: 2, text: '随便其他什么人吃的东西' }]

          }, 3000)
        },
        answerFun(text='确定删除?'){
          return new Promise((resolve,reject)=>{
            this.$confirm(text, '提示', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
              }).then(() => {
                resolve(true)
              }).catch(() => {
                resolve(false)        
            })
          })
        },
        async delRow(row) {
          let rel = await this.answerFun();
          if(!rel){
            // 点击了取消
            return
          }
          for (let i = 0; i < this.allRole.length; i++) {
            if (this.allRole[i].name == row.name) {
              this.allRole.splice(i, 1)
              break;
            }
          }
        }
      }
    })

  </script>

<div style="text-align:center;margin:50px 0; font:normal 14px/24px 'MicroSoft YaHei';">
<p>适用浏览器：Chrome、FireFox、360、搜狗、Opera、傲游. 不支持Windows版Safari、IE8及以下浏览器。</p>
<p>来源：<a href="http://sc.chinaz.com/" target="_blank">站长素材</a></p>
</div>
</body>
</html>